From 73eac1082dfafd0e855d4f45b536e12d7f641724 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 9 Sep 2005 13:28:23 +0000 Subject: [PATCH] pagefault handler fixes. --- xen/arch/x86/mm.c | 20 +++++++- xen/arch/x86/traps.c | 111 ++++++++++++++++++++++++------------------- 2 files changed, 81 insertions(+), 50 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 41fd471127..1bb0e7ba8c 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3185,7 +3185,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr, struct pfn_info *page; l1_pgentry_t pte; l2_pgentry_t *pl2e, l2e; - int which; + int which, flags; unsigned long l2_idx; if ( unlikely(shadow_mode_enabled(d)) ) @@ -3206,8 +3206,24 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr, pfn = l1e_get_pfn(pte); page = &frame_table[pfn]; +#ifdef CONFIG_X86_64 +#define WRPT_PTE_FLAGS (_PAGE_RW | _PAGE_PRESENT | _PAGE_USER) +#else +#define WRPT_PTE_FLAGS (_PAGE_RW | _PAGE_PRESENT) +#endif + + /* + * Check the required flags for a valid wrpt mapping. If the page is + * already writable then we can return straight to the guest (SMP race). + * We decide whether or not to propagate the fault by testing for write + * permissions in page directories by writing back to the linear mapping. + */ + if ( (flags = l1e_get_flags(pte) & WRPT_PTE_FLAGS) == WRPT_PTE_FLAGS ) + return !__put_user( + pte.l1, &linear_pg_table[l1_linear_offset(addr)].l1); + /* We are looking only for read-only mappings of p.t. pages. */ - if ( ((l1e_get_flags(pte) & (_PAGE_RW|_PAGE_PRESENT)) != _PAGE_PRESENT) || + if ( ((flags | _PAGE_RW) != WRPT_PTE_FLAGS) || ((page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table) || ((page->u.inuse.type_info & PGT_count_mask) == 0) || (page_get_owner(page) != d) ) diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 865204a72d..4f5be98865 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -470,20 +470,32 @@ static int handle_perdomain_mapping_fault( return EXCRET_fault_fixed; } -asmlinkage int do_page_fault(struct cpu_user_regs *regs) +#ifdef HYPERVISOR_VIRT_END +#define IN_HYPERVISOR_RANGE(va) \ + (((va) >= HYPERVISOR_VIRT_START) && ((va) < HYPERVISOR_VIRT_END)) +#else +#define IN_HYPERVISOR_RANGE(va) \ + (((va) >= HYPERVISOR_VIRT_START)) +#endif + +static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs) { - unsigned long addr, fixup; - struct vcpu *v = current; + struct vcpu *v = current; struct domain *d = v->domain; - __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : ); - - DEBUGGER_trap_entry(TRAP_page_fault, regs); - - perfc_incrc(page_faults); - - if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && - !shadow_mode_enabled(d)) ) + if ( unlikely(IN_HYPERVISOR_RANGE(addr)) ) + { + if ( shadow_mode_external(d) && GUEST_CONTEXT(v, regs) ) + return shadow_fault(addr, regs); + if ( (addr >= PERDOMAIN_VIRT_START) && (addr < PERDOMAIN_VIRT_END) ) + return handle_perdomain_mapping_fault( + addr - PERDOMAIN_VIRT_START, regs); + } + else if ( unlikely(shadow_mode_enabled(d)) ) + { + return shadow_fault(addr, regs); + } + else if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) ) { LOCK_BIGLOCK(d); if ( unlikely(d->arch.ptwr[PTWR_PT_ACTIVE].l1va) && @@ -495,14 +507,9 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) return EXCRET_fault_fixed; } - if ( ((addr < HYPERVISOR_VIRT_START) -#if defined(__x86_64__) - || (addr >= HYPERVISOR_VIRT_END) -#endif - ) - && - KERNEL_MODE(v, regs) && - ((regs->error_code & 3) == 3) && /* write-protection fault */ + if ( KERNEL_MODE(v, regs) && + /* Protection violation on write? No reserved-bit violation? */ + ((regs->error_code & 0xb) == 0x3) && ptwr_do_page_fault(d, addr, regs) ) { UNLOCK_BIGLOCK(d); @@ -511,43 +518,51 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) UNLOCK_BIGLOCK(d); } - if ( unlikely(shadow_mode_enabled(d)) && - ((addr < HYPERVISOR_VIRT_START) || -#if defined(__x86_64__) - (addr >= HYPERVISOR_VIRT_END) || -#endif - (shadow_mode_external(d) && GUEST_CONTEXT(v, regs))) && - shadow_fault(addr, regs) ) - return EXCRET_fault_fixed; + return 0; +} + +/* + * #PF error code: + * Bit 0: Protection violation (=1) ; Page not present (=0) + * Bit 1: Write access + * Bit 2: Supervisor mode + * Bit 3: Reserved bit violation + * Bit 4: Instruction fetch + */ +asmlinkage int do_page_fault(struct cpu_user_regs *regs) +{ + unsigned long addr, fixup; + int rc; - if ( unlikely(addr >= PERDOMAIN_VIRT_START) && - unlikely(addr < PERDOMAIN_VIRT_END) && - handle_perdomain_mapping_fault(addr - PERDOMAIN_VIRT_START, regs) ) - return EXCRET_fault_fixed; + __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : ); - if ( !GUEST_MODE(regs) ) - goto xen_fault; + DEBUGGER_trap_entry(TRAP_page_fault, regs); - propagate_page_fault(addr, regs->error_code); - return 0; + perfc_incrc(page_faults); - xen_fault: + if ( unlikely((rc = fixup_page_fault(addr, regs)) != 0) ) + return rc; - if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) + if ( unlikely(!GUEST_MODE(regs)) ) { - perfc_incrc(copy_user_faults); - regs->eip = fixup; - return 0; - } + if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) + { + perfc_incrc(copy_user_faults); + regs->eip = fixup; + return 0; + } - DEBUGGER_trap_fatal(TRAP_page_fault, regs); + DEBUGGER_trap_fatal(TRAP_page_fault, regs); - show_registers(regs); - show_page_walk(addr); - panic("CPU%d FATAL PAGE FAULT\n" - "[error_code=%04x]\n" - "Faulting linear address: %p\n", - smp_processor_id(), regs->error_code, addr); + show_registers(regs); + show_page_walk(addr); + panic("CPU%d FATAL PAGE FAULT\n" + "[error_code=%04x]\n" + "Faulting linear address: %p\n", + smp_processor_id(), regs->error_code, addr); + } + + propagate_page_fault(addr, regs->error_code); return 0; } -- 2.30.2